export default {
  // mime type [xls, csv], default: xls
  type: 'xls',
  // Json to download
  data: [],
  // fields inside the Json Object that you want to export
  // if no given, all the properties in the Json are exported
  fields: {},
  // Title for the data
  title: null,
  // filename to export, deault: data.xls
  name: 'data.xls',
  meta: [
    [
      {
        'key': 'charset',
        'value': 'utf-8'
      }
    ]
  ],

  generate() {
    if (!this.data.length) {
      return
    }
    let json = this.getProcessedJson(this.data, this.fields)
    if (this.type == 'csv') {
      return this.export(this.jsonToCSV(json), this.name, "application/csv");
    }
    return this.export(this.jsonToXLS(json), this.name, "application/vnd.ms-excel");
  },
  /*
  Use downloadjs to generate the download link
  */
  export: function (data, filename, mime) {
    let blob = this.base64ToBlob(data, mime)
    download(blob, filename, mime)
  },
  /*
  jsonToXLS
  ---------------
  Transform json data into an xml document with MS Excel format, sadly
  this format show a prompt when open due to a default behavior
  on Microsoft office. It's recommended to use CSV format instead.
  */
  jsonToXLS: function (data) {
    let xlsTemp = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta name=ProgId content=Excel.Sheet> <meta name=Generator content="Microsoft Excel 11"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>${table}</table></body></html>'
    let xlsData = '<thead><tr>'

    if (this.title != null) {
      if (Array.isArray(this.title)) {
        for (var i = 0; i < this.title.length; i++) {
          xlsData += '<th colspan="' + Object.keys(data[0]).length + '">' + this.title[i] + '<th></tr><tr>'
        }
      }
      else {
        xlsData += '<th colspan="' + Object.keys(data[0]).length + '">' + this.title + '<th></tr><tr>'
      }
    }

    for (let key in data[0]) {
      xlsData += '<th>' + key + '</th>'
    }
    xlsData += '</tr></thead>'
    xlsData += '<tbody>'

    data.map(function (item, index) {
      xlsData += '<tbody><tr>'
      for (let key in item) {
        xlsData += '<td>' + item[key] + '</td>'
      }
      xlsData += '</tr></tbody>'
    })
    return xlsTemp.replace('${table}', xlsData)
  },
  /*
  jsonToCSV
  ---------------
  Transform json data into an CSV file.
  */
  jsonToCSV: function (data) {
    var csvData = ''

    if (this.title != null) {
      if (Array.isArray(this.title)) {
        for (var i = 0; i < this.title.length; i++) {
          csvData += this.title[i] + '\r\n'
        }
      }
      else {
        csvData += this.title + '\r\n'
      }
    }

    for (let key in data[0]) {
      csvData += key + ','
    }
    csvData = csvData.slice(0, csvData.length - 1)
    csvData += '\r\n'

    data.map(function (item) {
      for (let key in item) {
        let escapedCSV = item[key] + '' // cast Numbers to string
        if (escapedCSV.match(/[,"\n]/)) {
          escapedCSV = '"' + escapedCSV.replace(/\"/g, "\"\"") + '"'
        }
        csvData += escapedCSV + ','
      }
      csvData = csvData.slice(0, csvData.length - 1)
      csvData += '\r\n'
    })
    return csvData
  },
  /*
  getProcessedJson
  ---------------
  Get only the data to export, if no fields are set return all the data
  */
  getProcessedJson: function (data, header) {
    let keys = this.getKeys(data, header)
    let newData = []
    let _self = this
    data.map(function (item, index) {
      let newItem = {}
      for (let label in keys) {
        var iii = item;
        let property = keys[label]
        newItem[label] = _self.getNestedData(property, item)
      }
      newData.push(newItem)
    })

    return newData
  },
  getKeys: function (data, header) {
    if (header) {
      return header
    }

    let keys = {}
    for (let key in data[0]) {
      keys[key] = key
    }
    return keys
  },
  callItemCallback: function (field, itemValue) {
    if (typeof field === 'object' && typeof field.callback === 'function') {
      return field.callback(itemValue);
    }

    return itemValue;
  },
  getNestedData: function (key, item) {
    const field = (typeof key === 'object') ? key.field : key;

    let valueFromNestedKey = null
    let keyNestedSplit = field.split(".")

    valueFromNestedKey = item[keyNestedSplit[0]]
    for (let j = 1; j < keyNestedSplit.length; j++) {
      valueFromNestedKey = valueFromNestedKey[keyNestedSplit[j]]
    }

    valueFromNestedKey = this.callItemCallback(key, valueFromNestedKey);

    return valueFromNestedKey;
  },
  base64ToBlob: function (data, mime) {
    let base64 = window.btoa(window.unescape(encodeURIComponent(data)))
    let bstr = atob(base64)
    let n = bstr.length
    let u8arr = new Uint8ClampedArray(n)
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return new Blob([u8arr], {type: mime})
  },
}